<?php

namespace IYUU\sdk\CoolQ;

use BadRequestException;
use InternalServerErrorException;
use IYUU\sdk\CoolQ\Event\Message as EventMessage;
use RuleKeywordModel;
use think\facade\Db;

/**
 * 模块消息路由器
 * Class ModulesRouter
 * @package IYUU\sdk\CoolQ
 */
class ModulesRouter
{
    /**
     * 模块调度入口
     * 功能：根据上下文Session或者消息内容，路由到对应的模块
     *
     * @param Context $context
     * @param EventMessage $msgObj
     * @return array|string
     * @throws BadRequestException
     * @throws InternalServerErrorException
     */
    public static function dispatcher(Context $context, EventMessage $msgObj)
    {
        /**
         * 1.先检查是否上下文消息路由
         */
        // 数据结构  $inContext = ['module' => 'basic', 'expire' => 1628168132];
        if ($inContext = static::inContext($context)) {
            /**
             * 2.1 YES上下文 ---> 消息路由至模块 ---> 回复成功
             */
            $module = $inContext['module'];
            return static::run($module, true, $context, $msgObj);
        }

        /**
         * 2.2 NO 上下文 ---> 查表，按优先级依次匹配，匹配模式（1内容等价、2关键字包含、3正则表达式）
         */
        return static::matchKeyword($context, $msgObj);
    }

    /**
     * 查表，按优先级依次匹配
     *
     * @param Context $context
     * @param EventMessage $msgObj
     * @return array|string
     * @throws BadRequestException
     * @throws InternalServerErrorException
     */
    private static function matchKeyword(Context $context, EventMessage $msgObj)
    {
        // 取用户本次发送过来的消息内容
        $message = $context->get('message');
        // 上下文过期，清理旧的关键字规则xxSession
        $context->unsetSession(Context::moduleRuleKeywordSession);
        /**
         * 2.2 NO 上下文 ---> 查表，按优先级依次匹配，匹配模式（1内容等价、2关键字包含、3正则表达式）
         */
        $where = [
            'bot_key' => 1,
            'status' => 1,
        ];
        $rule_keyword = Db::table(RuleKeywordModel::table_name)->where($where)->order('priority_order', 'desc')->cursor();
        // 循环匹配文本消息
        foreach ($rule_keyword as $row) {
            if (empty($row)) {
                return [];
            }
            // 调试日志
            //file_put_contents(runtime_path() . '/ModulesRouter.log', __METHOD__ . PP($row->toArray(), false), FILE_APPEND);
            $match_type = (int)$row['match_type']; // 匹配模式
            $content = $row['content'];   // 匹配内容
            $module = $row['module'];     // 模块名
            switch ($match_type) {
                case 1:     // 内容等价 strcasecmp不区分大小写、strcmp区分大小写
                    if (0 === strcasecmp($content, $message)) {
                        $context->setSession(Context::moduleRuleKeywordSession, $row);
                        return static::run($module, false, $context, $msgObj);
                    }
                    break;
                case 2:     // 关键字包含 stripos不区分大小写
                    if (stripos($message, $content) !== false) {
                        $context->setSession(Context::moduleRuleKeywordSession, $row);
                        return static::run($module, false, $context, $msgObj);
                    }
                    break;
                case 3:     // 正则表达式
                    // 正则匹配模式：i忽略大小写,s点号通配模式,U懒惰模式
                    if (preg_match('#' . $content . '#isU', $message, $matches)) {
                        $row['regex_matches'] = $matches;
                        $context->setSession(Context::moduleRuleKeywordSession, $row);
                        return static::run($module, false, $context, $msgObj);
                    }
                    break;
                default:
                    break;
            }
        }

        return [];
    }

    /**
     * 验证是否为上下文
     *
     * @param Context $context
     * @return array 正常返回数据结构 $inContext = ['module' => 'basic', 'expire' => 1628168132];
     */
    private static function inContext(Context $context): array
    {
        $inContext = $context->getSession(Context::moduleInContextSession);
        if ($inContext) {
            if (!empty($inContext['module']) && !empty($inContext['expire']) && ($inContext['expire'] > BOT_REQUEST_TIME)) {
                return $inContext;
            }
            // 上下文过期，清理上下文Session
            $context->unsetSession(Context::moduleInContextSession);
        }
        return [];
    }

    /**
     * 实例化模块，运行默认应答方法
     *
     * @param string $module
     * @param bool $inContext
     * @param Context $context
     * @param EventMessage $msgObj
     * @return array|string
     * @throws BadRequestException
     * @throws InternalServerErrorException
     */
    private static function run(string $module, bool $inContext, Context $context, EventMessage $msgObj)
    {
        $moduleClassName = "\\IYUU\\sdk\\CoolQ\\Modules\\" . $module . "\\processor";
        if (!class_exists($moduleClassName)) {
            throw new BadRequestException("{$module} 模块不存在", 1);
        }
        $module = new $moduleClassName($inContext);
        if ($module instanceof ModulesProcessor) {
            return $module->respond($context, $msgObj);
        }

        throw new InternalServerErrorException("$moduleClassName 没有继承抽象类：" . ModulesProcessor::class);
    }
}
